package cn.iocoder.yudao.module.reading.service.file;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.infra.controller.admin.file.vo.file.FilePresignedUrlRespVO;
import cn.iocoder.yudao.module.infra.service.file.FileService;
import cn.iocoder.yudao.module.infra.service.file.FileConfigService;
import cn.iocoder.yudao.module.infra.framework.file.core.client.FileClient;
import cn.iocoder.yudao.module.reading.enums.FilePathConstants;
import cn.iocoder.yudao.module.reading.util.FilePathUtils;
import cn.iocoder.yudao.module.reading.framework.util.StaticResourceUrlUtils;
import cn.iocoder.yudao.module.reading.util.AudioMetadataUtils;
import cn.iocoder.yudao.module.reading.controller.admin.file.vo.AudioUploadRespVO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

/**
 * 绘本阅读应用文件服务实现类
 * 
 * @author 李晨
 */
@Service
@Slf4j
public class ReadingFileServiceImpl implements ReadingFileService {

    @Resource
    private FileService fileService;

    @Resource
    private FileConfigService fileConfigService;

    @Resource
    private StaticResourceUrlUtils staticResourceUrlUtils;

    // =============================================
    // 用户相关文件上传
    // =============================================

    @Override
    public String uploadUserAvatar(Long userId, MultipartFile avatarFile) {
        log.info("上传用户头像，用户ID: {}, 文件名: {}", userId, avatarFile.getOriginalFilename());
        
        // 验证文件
        validateImageFile(avatarFile, FilePathConstants.MAX_AVATAR_SIZE);
        
        // 生成文件路径
        String directory = FilePathUtils.generateUserAvatarPath(userId, avatarFile.getOriginalFilename());
        
        // 上传文件
        return uploadFile(avatarFile, directory);
    }

    @Override
    public String uploadUserRecording(Long userId, Long bookId, Long pageId, MultipartFile recordingFile) {
        log.info("上传用户配音，用户ID: {}, 绘本ID: {}, 页面ID: {}, 文件名: {}", userId, bookId, pageId, recordingFile.getOriginalFilename());

        // 验证文件
        validateAudioFile(recordingFile, FilePathConstants.MAX_AUDIO_SIZE);

        // 生成目录路径和文件名
        String directory = FilePathUtils.generateUserRecordingPath(userId, bookId, pageId, recordingFile.getOriginalFilename());
        String fileName = FilePathUtils.generateUserRecordingFileName(recordingFile.getOriginalFilename());

        log.info("🔧 生成的目录路径: {}, 文件名: {}", directory, fileName);

        // 上传文件
        return uploadFileWithCustomName(recordingFile, directory, fileName);
    }

    // =============================================
    // 绘本相关文件上传
    // =============================================

    @Override
    public String uploadBookCover(Long bookSetId, Long bookId, MultipartFile coverFile) {
        log.info("上传绘本封面，绘本集ID: {}, 绘本ID: {}, 文件名: {}", bookSetId, bookId, coverFile.getOriginalFilename());
        
        // 验证文件
        validateImageFile(coverFile, FilePathConstants.MAX_BOOK_COVER_SIZE);
        
        // 生成文件路径
        String directory = FilePathUtils.generateBookCoverPath(bookSetId, bookId, coverFile.getOriginalFilename());
        
        // 上传文件
        return uploadFile(coverFile, directory);
    }

    @Override
    public String uploadBookPage(Long bookSetId, Long bookId, Integer pageNumber, MultipartFile pageFile) {
        log.info("上传绘本页面，绘本集ID: {}, 绘本ID: {}, 页码: {}, 文件名: {}", 
                bookSetId, bookId, pageNumber, pageFile.getOriginalFilename());
        
        // 验证文件
        validateImageFile(pageFile, FilePathConstants.MAX_BOOK_PAGE_SIZE);
        
        // 生成文件路径
        String directory = FilePathUtils.generateBookPagePath(bookSetId, bookId, pageNumber, pageFile.getOriginalFilename());
        
        // 上传文件
        return uploadFile(pageFile, directory);
    }

    @Override
    public String uploadBookAudio(Long bookSetId, Long bookId, Integer pageNumber, MultipartFile audioFile) {
        log.info("上传绘本音频，绘本集ID: {}, 绘本ID: {}, 页码: {}, 文件名: {}", 
                bookSetId, bookId, pageNumber, audioFile.getOriginalFilename());
        
        // 验证文件
        validateAudioFile(audioFile, FilePathConstants.MAX_AUDIO_SIZE);
        
        // 生成文件路径
        String directory = FilePathUtils.generateBookAudioPath(bookSetId, bookId, pageNumber, audioFile.getOriginalFilename());
        
        // 上传文件
        return uploadFile(audioFile, directory);
    }

    // =============================================
    // 绘本集相关文件上传
    // =============================================

    @Override
    public String uploadBookSetCover(Long bookSetId, MultipartFile coverFile) {
        return uploadBookSetCover(bookSetId, coverFile, null);
    }

    @Override
    public String uploadBookSetCover(Long bookSetId, MultipartFile coverFile, String oldCoverPath) {
        log.info("上传绘本集封面，绘本集ID: {}, 文件名: {}, 旧文件路径: {}",
                bookSetId, coverFile.getOriginalFilename(), oldCoverPath);

        // 验证文件
        validateImageFile(coverFile, FilePathConstants.MAX_BOOK_COVER_SIZE);

        // 生成文件路径
        String directory = FilePathUtils.generateBookSetCoverPath(bookSetId, coverFile.getOriginalFilename());

        // 上传新文件
        String newFilePath = uploadFile(coverFile, directory);

        // 删除旧文件（如果存在且与新文件不同）
        if (StrUtil.isNotEmpty(oldCoverPath) && !oldCoverPath.equals(newFilePath)) {
            deleteFile(oldCoverPath);
            log.info("已删除旧的绘本集封面文件: {}", oldCoverPath);
        }

        return newFilePath;
    }

    // =============================================
    // 音频资源文件上传
    // =============================================

    @Override
    public AudioUploadRespVO uploadAudioResource(String category, String language, MultipartFile audioFile) {
        log.info("上传音频资源，分类: {}, 语言: {}, 文件名: {}", category, language, audioFile.getOriginalFilename());

        // 验证文件
        validateAudioFile(audioFile, FilePathConstants.MAX_AUDIO_SIZE);

        // 解析音频时长
        Integer duration = AudioMetadataUtils.getAudioDuration(audioFile);
        log.info("解析音频时长: {} 秒", duration);

        // 生成文件路径
        String directory = FilePathUtils.generateAudioResourcePath(category, language, audioFile.getOriginalFilename());

        // 上传文件并获取完整URL
        String fullUrl = uploadFile(audioFile, directory);
        log.info("音频资源上传成功，完整URL: {}, 时长: {} 秒", fullUrl, duration);

        // 构建响应对象
        AudioUploadRespVO respVO = new AudioUploadRespVO();
        respVO.setAudioUrl(fullUrl);
        respVO.setDuration(duration);
        respVO.setDurationText(AudioMetadataUtils.formatDuration(duration));
        respVO.setFileSize(audioFile.getSize());
        respVO.setOriginalFileName(audioFile.getOriginalFilename());

        return respVO;
    }

    @Override
    public String uploadAudioCover(Long audioId, MultipartFile coverFile) {
        log.info("上传音频封面，音频ID: {}, 文件名: {}", audioId, coverFile.getOriginalFilename());

        // 验证文件
        validateImageFile(coverFile, FilePathConstants.MAX_BOOK_COVER_SIZE);

        // 生成文件路径
        String directory = FilePathUtils.generateAudioCoverPath(audioId, coverFile.getOriginalFilename());

        // 上传文件并获取完整URL
        String fullUrl = uploadFile(coverFile, directory);
        log.info("音频封面上传成功，完整URL: {}", fullUrl);

        return fullUrl;
    }

    // =============================================
    // 文件删除方法
    // =============================================

    @Override
    public boolean deleteBookSetCover(String relativePath) {
        return deleteFile(relativePath);
    }

    @Override
    public boolean deleteBookCover(String relativePath) {
        return deleteFile(relativePath);
    }

    @Override
    public boolean deleteBookPageImage(String relativePath) {
        return deleteFile(relativePath);
    }

    @Override
    public boolean deleteBookAudio(String relativePath) {
        return deleteFile(relativePath);
    }

    @Override
    public boolean deleteFile(String pathOrUrl) {
        if (StrUtil.isEmpty(pathOrUrl)) {
            log.warn("删除文件失败：文件路径为空");
            return false;
        }

        try {
            // 将输入转换为相对路径（如果是完整URL则提取路径部分）
            String relativePath = staticResourceUrlUtils.toRelativePath(pathOrUrl);

            // 从相对路径中提取文件路径（去掉开头的/）
            String filePath = relativePath;
            if (filePath.startsWith("/")) {
                filePath = filePath.substring(1);
            }

            log.info("删除文件 - 原始输入: {}, 相对路径: {}, 文件路径: {}", pathOrUrl, relativePath, filePath);

            // 获取主文件客户端
            FileClient fileClient = fileConfigService.getMasterFileClient();
            if (fileClient == null) {
                log.error("获取文件客户端失败");
                return false;
            }

            // 直接通过文件客户端删除文件
            fileClient.delete(filePath);

            log.info("文件删除成功，路径: {}", relativePath);
            return true;
        } catch (Exception e) {
            log.error("删除文件失败，路径: {}", pathOrUrl, e);
            return false;
        }
    }

    // =============================================
    // 预签名URL获取
    // =============================================

    @Override
    public FilePresignedUrlRespVO getUserAvatarPresignedUrl(Long userId, String fileName) {
        String directory = FilePathUtils.generateUserAvatarPath(userId, fileName);
        return fileService.getFilePresignedUrl(fileName, directory);
    }

    @Override
    public FilePresignedUrlRespVO getBookCoverPresignedUrl(Long bookSetId, Long bookId, String fileName) {
        String directory = FilePathUtils.generateBookCoverPath(bookSetId, bookId, fileName);
        return fileService.getFilePresignedUrl(fileName, directory);
    }

    @Override
    public FilePresignedUrlRespVO getBookPagePresignedUrl(Long bookSetId, Long bookId, Integer pageNumber, String fileName) {
        String directory = FilePathUtils.generateBookPagePath(bookSetId, bookId, pageNumber, fileName);
        return fileService.getFilePresignedUrl(fileName, directory);
    }

    @Override
    public FilePresignedUrlRespVO getAudioResourcePresignedUrl(String category, String language, String fileName) {
        String directory = FilePathUtils.generateAudioResourcePath(category, language, fileName);
        return fileService.getFilePresignedUrl(fileName, directory);
    }

    // =============================================
    // 文件验证方法
    // =============================================

    @Override
    public void validateImageFile(MultipartFile file, long maxSize) {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }
        
        // 检查文件大小
        if (file.getSize() > maxSize) {
            throw new IllegalArgumentException("文件大小超过限制，最大允许: " + (maxSize / 1024 / 1024) + "MB");
        }
        
        // 检查文件类型
        String contentType = file.getContentType();
        if (!FilePathConstants.isSupportedImageType(contentType)) {
            throw new IllegalArgumentException("不支持的图片格式，支持的格式: jpg, png, gif, webp");
        }
    }

    @Override
    public void validateAudioFile(MultipartFile file, long maxSize) {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }
        
        // 检查文件大小
        if (file.getSize() > maxSize) {
            throw new IllegalArgumentException("文件大小超过限制，最大允许: " + (maxSize / 1024 / 1024) + "MB");
        }
        
        // 检查文件类型
        String contentType = file.getContentType();
        if (!FilePathConstants.isSupportedAudioType(contentType)) {
            throw new IllegalArgumentException("不支持的音频格式，支持的格式: mp3, wav, ogg, aac, m4a");
        }
    }

    // =============================================
    // 私有工具方法
    // =============================================

    /**
     * 通用文件上传方法
     * 上传文件并返回相对路径（用于数据库存储）
     */
    /**
     * 上传文件并使用自定义文件名
     */
    private String uploadFileWithCustomName(MultipartFile file, String directory, String customFileName) {
        try {
            byte[] content = IoUtil.readBytes(file.getInputStream());

            log.info("🔧 文件上传调试 - 原始文件名: {}, 自定义文件名: {}, 目录: {}",
                    file.getOriginalFilename(), customFileName, directory);

            // 调用基础文件服务上传文件，根据配置返回相对路径或完整URL
            String url = fileService.createFile(content, customFileName, directory, file.getContentType());

            log.info("🔧 基础文件服务返回的URL: {}", url);
            log.info("🔧 URL是否为相对路径: {}", !url.startsWith("http"));

            // 直接返回文件服务返回的URL（可能是相对路径或完整URL，取决于配置）
            return url;
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new RuntimeException("文件上传失败: " + e.getMessage());
        }
    }

    private String uploadFile(MultipartFile file, String directory) {
        try {
            byte[] content = IoUtil.readBytes(file.getInputStream());
            String fileName = FilePathUtils.sanitizeFileName(file.getOriginalFilename());

            log.info("🔧 文件上传调试 - 原始文件名: {}, 清理后文件名: {}, 目录: {}",
                    file.getOriginalFilename(), fileName, directory);

            // 调用基础文件服务上传文件，根据配置返回相对路径或完整URL
            String url = fileService.createFile(content, fileName, directory, file.getContentType());

            log.info("🔧 基础文件服务返回的URL: {}", url);
            log.info("🔧 URL是否为相对路径: {}", !url.startsWith("http"));

            // 直接返回文件服务返回的URL（可能是相对路径或完整URL，取决于配置）
            return url;
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new RuntimeException("文件上传失败: " + e.getMessage());
        }
    }
}
